import { JSONSchema4 } from 'json-schema';
import { LiteralUnion, OmitStrict } from 'vtils/types';

export interface ChangeCase {
  /**
   * @example
   * changeCase.camelCase('test string') // => 'testString'
   */
  camelCase: (value: string) => string;
  /**
   * @example
   * changeCase.constantCase('test string') // => 'TEST_STRING'
   */
  constantCase: (value: string) => string;
  /**
   * @example
   * changeCase.dotCase('test string') // => 'test.string'
   */
  dotCase: (value: string) => string;
  /**
   * @example
   * changeCase.headerCase('test string') // => 'Test-String'
   */
  headerCase: (value: string) => string;
  /**
   * @example
   * changeCase.lowerCase('TEST STRING') // => 'test string'
   */
  lowerCase: (value: string) => string;
  /**
   * @example
   * changeCase.lowerCaseFirst('TEST') // => 'tEST'
   */
  lowerCaseFirst: (value: string) => string;
  /**
   * @example
   * changeCase.paramCase('test string') // => 'test-string'
   */
  paramCase: (value: string) => string;
  /**
   * @example
   * changeCase.pascalCase('test string') // => 'TestString'
   */
  pascalCase: (value: string) => string;
  /**
   * @example
   * changeCase.pathCase('test string') // => 'test/string'
   */
  pathCase: (value: string) => string;
  /**
   * @example
   * changeCase.sentenceCase('testString') // => 'Test string'
   */
  sentenceCase: (value: string) => string;
  /**
   * @example
   * changeCase.snakeCase('test string') // => 'test_string'
   */
  snakeCase: (value: string) => string;
  /**
   * @example
   * changeCase.swapCase('Test String') // => 'tEST sTRING'
   */
  swapCase: (value: string) => string;
  /**
   * @example
   * changeCase.titleCase('a simple test') // => 'A Simple Test'
   */
  titleCase: (value: string) => string;
  /**
   * @example
   * changeCase.upperCase('test string') // => 'TEST STRING'
   */
  upperCase: (value: string) => string;
  /**
   * @example
   * changeCase.upperCaseFirst('test') // => 'Test'
   */
  upperCaseFirst: (value: string) => string;
}

export interface ICommanderOpts {
  // 配置文件路径
  config: string;
  // 是否生成apis
  // apis: boolean;
}

export interface IProjects {
  /**
   * 项目token
   */
  token: string;
  /**
   * 需要排除的分类id
   */
  excludeCatIds?: number | number[];
  /**
   * 需要排除的接口id
   */
  excludeApiIds?: number | number[];
  /**
   * 需要输出的分类id
   *
   * 指定输出范围后，则只输出所包含的api
   *
   * 该api与excludeCatIds、excludeApiIds互斥
   */
  includeCatIds?: number | number[];
  /**
   * 需要输出的接口id
   *
   * 指定输出范围后，则只输出所包含的api
   *
   * 该api与excludeCatIds、excludeApiIds互斥
   */
  includeApiIds?: number | number[];
  /**
   * 处理输出api目录，ps：基于`outputFilePath`下的目录
   * @param apiData 接口yapi json
   * @param changeCase @see https://www.npmjs.com/package/change-case
   * @returns api目录名
   */
  getApiDir?: (apiData: Partial<Interface>, changeCase: ChangeCase) => string;
  /**
   * 自定义接口函数名称、出参入参数据类型名称
   * @param apiData 接口yapi json
   * @param changeCase @see https://www.npmjs.com/package/change-case
   * @returns { requestFunctionName: string; requestDataTypeName: string; responseDataTypeName: string; }
   */
  getApiNames?: (apiData: Partial<Interface>, changeCase: ChangeCase) => GetApiNamesType;
}

export interface IServerConfig {
  /**
   * YApi 服务地址
   * @example https://yapi.baibu.la/
   */
  serverUrl: string;
  /**
   * 输出的文件夹，默认 'src/api'
   */
  outputFilePath?: string;
  /**
   * 是否只生产types（没有api）
   * 默认为 false
   */
  typesOnly?: boolean;
  /**
   * api存放的
   */
  // apiFilePath?: string;
  /**
   * 获取 api 模板
   */
  getApiTemplate?: (data: GetApiNamesType, interfaceInfo: Interface) => string;
  /**
   * 各种项目配置
   */
  projects: IProjects[];
  /**
   * data key 默认为 data
   */
  dataKey?: string;
}

export type TMixConfig = Partial<OmitStrict<IServerConfig, 'projects'> & IProjects>;

/** 属性定义 */
export interface PropDefinition {
  /** 属性名称 */
  name: string;
  /** 是否必需 */
  required: boolean;
  /** 类型 */
  type: JSONSchema4['type'];
  /** 注释 */
  comment: string;
}

/** 属性定义列表 */
export type PropDefinitions = PropDefinition[];

export interface OutputFilePath {
  [dir: string]: {
    config: TMixConfig;
    content: string[];
    // api methods 的文件 -- 暂不支持
    // apiFilePath: string;
  };
}

/** 请求方式 */
export enum Method {
  GET = 'GET',
  POST = 'POST',
  PUT = 'PUT',
  DELETE = 'DELETE',
  HEAD = 'HEAD',
  OPTIONS = 'OPTIONS',
  PATCH = 'PATCH'
}

/** 请求数据类型 */
export enum RequestBodyType {
  /** 查询字符串 */
  query = 'query',
  /** 表单 */
  form = 'form',
  /** JSON */
  json = 'json',
  /** 纯文本 */
  text = 'text',
  /** 文件 */
  file = 'file',
  /** 原始数据 */
  raw = 'raw',
  /** 无请求数据 */
  none = 'none'
}

/** 是否必需 */
export enum Required {
  /** 不必需 */
  false = '0',
  /** 必需 */
  true = '1'
}

/** 请求表单条目类型 */
export enum RequestFormItemType {
  /** 纯文本 */
  text = 'text',
  /** 文件 */
  file = 'file'
}

/** 返回数据类型 */
export enum ResponseBodyType {
  /** JSON */
  json = 'json',
  /** 纯文本 */
  text = 'text',
  /** XML */
  xml = 'xml',
  /** 原始数据 */
  raw = 'raw'

  // yapi 实际上返回的是 json，有另外的字段指示其是否是 json schema
  /** JSON Schema */
  // jsonSchema = 'json-schema',
}

/** 接口定义 */
export interface Interface {
  /** 接口 ID */
  _id: number;
  /** 所属分类信息 */
  _category: Omit<Category, 'list'>;
  /** 接口名称 */
  title: string;
  /** 状态 */
  status: LiteralUnion<'done' | 'undone', string>;
  /** 接口备注 */
  markdown: string;
  /** 请求路径 */
  path: string;
  /** 请求方式，HEAD、OPTIONS 处理与 GET 相似，其余处理与 POST 相似 */
  method: Method;
  /** 所属项目 id */
  project_id: number;
  /** 所属分类 id */
  catid: number;
  /** 标签列表 */
  tag: string[];
  /** 路径参数 */
  req_params: Array<{
    /** 名称 */
    name: string;
    /** 备注 */
    desc: string;
    /** 示例 */
    example: string;
  }>;
  /** 仅 GET：请求串 */
  req_query: Array<{
    /** 名称 */
    name: string;
    /** 备注 */
    desc: string;
    /** 示例 */
    example: string;
    /** 是否必需 */
    required: Required;
  }>;
  /** 仅 POST：请求内容类型。为 text, file, raw 时不必特殊处理。 */
  req_body_type: RequestBodyType;
  /** `req_body_type = json` 时是否为 json schema */
  req_body_is_json_schema: boolean;
  /** `req_body_type = form` 时的请求内容 */
  req_body_form: Array<{
    /** 名称 */
    name: string;
    /** 类型 */
    type: RequestFormItemType;
    /** 备注 */
    desc: string;
    /** 示例 */
    example: string;
    /** 是否必需 */
    required: Required;
  }>;
  /** `req_body_type = json` 时的请求内容 */
  req_body_other: string;
  /** 返回数据类型 */
  res_body_type: ResponseBodyType;
  /** `res_body_type = json` 时是否为 json schema */
  res_body_is_json_schema: boolean;
  /** 返回数据 */
  res_body: string;
  /** 创建时间（unix时间戳） */
  add_time: number;
  /** 更新时间（unix时间戳） */
  up_time: number;
  [key: string]: any;
}

/** 接口列表 */
export type InterfaceList = Interface[];

/** 分类信息 */
export interface Category {
  /**
   * 好像没什么意义的index
   */
  index: number;
  /** 分类名称 */
  name: string;
  /** 分类备注 */
  desc: string;
  /** 分类接口列表 */
  list: InterfaceList;
  /** 创建时间（unix时间戳） */
  add_time: number;
  /** 更新时间（unix时间戳） */
  up_time: number;
}

export interface InterfaceCodeTemplateData {
  interfaceApiTitle: string;
  interfaceApiUrl: string;
  interfaceExtraComments: string;
  requestDataType: string;
  responseDataType: string;
  // paramNameType: string;
  // paramNamesLiteral: string;
  requestDataTypeName: string;
  responseDataTypeName: string;
  // interfaceInfo: Interface;
  isRequestDataOptional: boolean;
}

export interface GetApiNamesType extends OmitStrict<InterfaceCodeTemplateData, 'responseDataType'> {
  requestFunctionName: string;
  // 路径请求参数
  paramNames: string[];
}
